#include "VideoWapper.h"
#include "sockutil.h"
using namespace  toolkit;
VideoWapper::VideoWapper()
{
	NetMgr::GetInstance()->Init();
}

VideoWapper::~VideoWapper()
{
	ReleaseConnect();
}

int32_t VideoWapper::Connect()
{
	m_task_scheduler = NetMgr::GetInstance()->m_oEventLoop.GetTaskScheduler(); 
	m_readBuffer.resize(RevBufferSize);
	return int32_t();
}

void VideoWapper::ReleaseConnect()
{
	if (m_task_scheduler)
	{

		m_task_scheduler->InvokTask([this]()
			{
				if (m_thread)
				{
					m_bExit = true;
					if (m_thread->joinable())
					{
						m_thread->join();
						delete m_thread;
						m_thread = NULL;
					}
				}
				if (socket_fd > 0)
				{
					ChannelPtr channel = std::make_shared<Channel>(socket_fd);
					m_task_scheduler->RemoveChannel(channel);

					close(socket_fd);
					socket_fd = 0;
				}
				if (m_RtpToPcap)
				{
					m_RtpToPcap->close();
				}
			});

		if (m_iTimerId > 0)
		{
			m_task_scheduler->DelTimer(m_iTimerId);
			m_iTimerId = -1;
		}
		
	}
}

int32_t VideoWapper::SetRemoteSDP(VideoWapperParams& oVideoWapperParams)
{
	m_VideoWapperParams = oVideoWapperParams;
	int32_t ret = 0;
	int32_t error = 0;
	do 
	{
		if (!m_task_scheduler)
		{
			ret = -1;
			break;
		}
		
		m_task_scheduler->InvokTask([this, oVideoWapperParams, &error]()
			{
				if (0 == oVideoWapperParams.m_ip_type)
				{
					socket_fd = toolkit::SockUtil::bindUdpSock(oVideoWapperParams.m_local_port, oVideoWapperParams.m_local_ip.c_str());
				}
				else
				{
					socket_fd = toolkit::SockUtil::connect(oVideoWapperParams.m_remote_ip.c_str(), oVideoWapperParams.m_remote_port);
				}
				m_remote_addr = toolkit::SockUtil::make_sockaddr(m_VideoWapperParams.m_remote_ip.c_str(), m_VideoWapperParams.m_remote_port);
				if (socket_fd <= 0)
				{
					error = -1;
				}

				ChannelPtr channel = std::make_shared<Channel>(socket_fd);
				channel->SetReadCallback(std::bind(&VideoWapper::OnReadCallBack, this));
				channel->EnableReading();
				error = m_task_scheduler->UpdateChannel(channel);
				if (error != 0)
				{
					error = -2;
					printf("UpdateChannel error :%d \n", error);
				}

				if (!m_VideoWapperParams.m_pcap_sender.empty())
				{
					int error = m_CRtpManage.init(m_VideoWapperParams.m_pcap_sender.c_str());
					if (0 != error)
					{
						error = -3;
						printf("m_CRtpManage.init error :%d \n", error);
					}
				}
				if (!m_thread)
				{
					m_thread = new std::thread(&VideoWapper::ThreadFun, this);
				}
				if (!m_thread)
				{
					error = -4;
				}

				if (!m_VideoWapperParams.m_pcap_receive.empty())
				{

					m_RtpToPcap = RtpToPcap::create();
					error = m_RtpToPcap->open(m_VideoWapperParams.m_pcap_receive.c_str());
					if (0 != error)
					{
						error = -5;
					}
					
				}
			
			});

		if (error != 0)
		{
			printf("VideoWapper::SetRemoteSDP error :%d \n", error);
			ret = -2;
			break;
		}
		auto cb = std::bind(&VideoWapper::TimerFun, this);

		m_iTimerId = m_task_scheduler->AddTimer(10, cb);
		if (m_iTimerId <= 0)
		{
			printf("UpdateChannel error m_iTimerId:%lld \n", m_iTimerId);
			ret = -4;
			break;
		}


	} while (0);

	if (0 != ret)
	{
		printf("VideoWapper::SetRemoteSDP error ret:%d \n", ret);
	}

	return ret;

}
int32_t VideoWapper::IncomingRtp(const int8_t* data, int32_t len)
{

	int ret = 0;
	if (m_task_scheduler)
	{
		m_task_scheduler->InvokTask([data, len, &ret, this]()
			{
				int  addr_len = sizeof(m_remote_addr);
				
				ret = sendto(socket_fd, (const char *)data, len, 0, (const sockaddr*)&m_remote_addr, addr_len);
				if (ret < 0)
				{
					printf("sendto errror ret:%d \n", ret);
				}
			});
	}
	return ret;
}
bool VideoWapper::TimerFun()
{
	//printf("VideoWapper::TimerFun time:%lld \n", m_task_scheduler->getCurrentTicket());


	return true;
}
void VideoWapper::ThreadFun()
{
	while (!m_bExit)
	{
		if (!m_VideoWapperParams.m_pcap_sender.empty())
		{
			uint64_t ms = 0;
			uint64_t lastms = 0;

			long long t_sender_use = 0;

			std::list<shared_ptr<rtpPacket> > olistRtp;
			m_CRtpManage.getList(olistRtp);
			std::list<shared_ptr<rtpPacket>>::iterator it = olistRtp.begin();
			int k = 0;
			int iRet = 0;
			do
			{
				shared_ptr<rtpPacket> pkt = *it;
				ms = pkt->getTs();

				int nServAddLen = sizeof(m_remote_addr);

				if (lastms != 0)
				{
					int64_t t_wait = ms - lastms - t_sender_use;

					printf("t_wait:%lld ms:%llu lastmu:%llu t_sender_use:%lld k:%d \n", t_wait, ms, lastms, t_sender_use, k);
					k++;

					if (t_wait > 0)
					{
						std::this_thread::sleep_for(std::chrono::milliseconds(t_wait));
						lastms = ms;
					}
				}
				// 首次执行
				else
				{
					lastms = ms;
				}

				long long t_1 = m_task_scheduler->getCurrentTicket();
				/*	iRet = sendto(m_socket, pkt->getHeader(), pkt->getPktLen(), 0, (sockaddr*)&m_remoteAddr, nServAddLen);
					if (iRet == SOCKET_ERROR) {
						printf("sendto() failed:\n");
						break;
					}*/
				iRet = sendto(socket_fd, pkt->getHeader(), pkt->getPktLen(), 0, (const sockaddr*)&m_remote_addr, nServAddLen);
				if (iRet == SOCKET_ERROR)
				{
					printf("sendto errror ret:%d \n", iRet);
					break;
				}
				long long t_2 = m_task_scheduler->getCurrentTicket();
				t_sender_use = t_2 - t_1;

				it++;
			} while (it != olistRtp.end());
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(20));
	}
	
}
void VideoWapper::OnReadCallBack()
{

	int  addr_len = sizeof(sockaddr_storage);
	sockaddr_storage tsockaddr_storage;
	int n = recvfrom(socket_fd, (char*)m_readBuffer.data(), RevBufferSize, 0, (sockaddr*)&tsockaddr_storage, &addr_len);
	if (n < 0)
	{
		return;
	}
	if (m_RtpToPcap)
	{
		m_RtpToPcap->writeRtpPacket((const uint8_t *)m_readBuffer.data(), n);

	}

	printf("Recv... ret: ret_send: ret:%d \n", n);
}
